package com.cliff.joinme.toolkit;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;

import com.cliff.joinme.toolkit.NanoHTTPD.Response;

public class MicroHTTPD extends NanoHTTPD {

	protected static int PORT = 8192;
	ArrayList<String> mFileList = null;
	
	protected final String PREFIX_LIST_URL = "/list/"; 

	public MicroHTTPD(ArrayList<String> fileList) throws IOException {
		super(PORT, null);
		mFileList = fileList;
	}

	public Response serveFile(String uri, Properties header) {
		Response res = null;

		File f = new File(uri);
		if (res == null && !f.exists())
			res = new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
					"Error 404, file not found.");

		// List the directory, if necessary
		if (res == null && f.isDirectory()) {
			res = new Response(HTTP_FORBIDDEN, MIME_PLAINTEXT,
					"FORBIDDEN: No directory listing.");
		}

		try {
			if (res == null) {
				// Get MIME type from file name extension, if possible
				String mime = null;
				int dot = f.getCanonicalPath().lastIndexOf('.');
				if (dot >= 0)
					mime = (String) theMimeTypes.get(f.getCanonicalPath()
							.substring(dot + 1).toLowerCase());
				if (mime == null)
					mime = MIME_DEFAULT_BINARY;

				// Calculate etag
				String etag = Integer.toHexString((f.getAbsolutePath()
						+ f.lastModified() + "" + f.length()).hashCode());

				// Support (simple) skipping:
				long startFrom = 0;
				long endAt = -1;
				String range = header.getProperty("range");
				if (range != null) {
					if (range.startsWith("bytes=")) {
						range = range.substring("bytes=".length());
						int minus = range.indexOf('-');
						try {
							if (minus > 0) {
								startFrom = Long.parseLong(range.substring(0,
										minus));
								endAt = Long.parseLong(range
										.substring(minus + 1));
							}
						} catch (NumberFormatException nfe) {
						}
					}
				}

				// Change return code and add Content-Range header when skipping
				// is requested
				long fileLen = f.length();
				if (range != null && startFrom >= 0) {
					if (startFrom >= fileLen) {
						res = new Response(HTTP_RANGE_NOT_SATISFIABLE,
								MIME_PLAINTEXT, "");
						res.addHeader("Content-Range", "bytes 0-0/" + fileLen);
						res.addHeader("ETag", etag);
					} else {
						if (endAt < 0)
							endAt = fileLen - 1;
						long newLen = endAt - startFrom + 1;
						if (newLen < 0)
							newLen = 0;

						final long dataLen = newLen;
						FileInputStream fis = new FileInputStream(f) {
							public int available() throws IOException {
								return (int) dataLen;
							}
						};
						fis.skip(startFrom);

						res = new Response(HTTP_PARTIALCONTENT, mime, fis);
						res.addHeader("Content-Length", "" + dataLen);
						res.addHeader("Content-Range", "bytes " + startFrom
								+ "-" + endAt + "/" + fileLen);
						res.addHeader("ETag", etag);
					}
				} else {
					if (etag.equals(header.getProperty("if-none-match")))
						res = new Response(HTTP_NOTMODIFIED, mime, "");
					else {
						res = new Response(HTTP_OK, mime,
								new FileInputStream(f));
						res.addHeader("Content-Length", "" + fileLen);
						res.addHeader("ETag", etag);
					}
				}
			}
		} catch (IOException ioe) {
			res = new Response(HTTP_FORBIDDEN, MIME_PLAINTEXT,
					"FORBIDDEN: Reading file failed.");
		}

		res.addHeader("Accept-Ranges", "bytes"); // Announce that the file
													// server accepts partial
													// content requestes
		return res;
	}
	
	@Override
	public Response serve(String uri, String method,
			Properties header, Properties parms, Properties files) {
		if (uri.startsWith(PREFIX_LIST_URL)) {
			try {
				int pos = Integer.parseInt(uri.substring(PREFIX_LIST_URL.length()));
				if ((pos < 0) || (pos >= mFileList.size())) {
					return new Response(HTTP_NOTFOUND,
							MIME_PLAINTEXT,
							"Error 404, Array out of bounds.");
				}
				return serveFile(mFileList.get(pos), header);
			} catch (Exception ex) {
				return new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
						"Error 404, Invalid URL.");
			}
		} else
			return new Response(HTTP_NOTFOUND, MIME_PLAINTEXT,
					"Error 404, file not found.");
	}

	public String getListUrl(int pos) {		
		return "http://" + ControlPointManager.getInstance().getLocalIpAddress() + ":" + PORT
				+ PREFIX_LIST_URL + pos;
	}

	@Override
	public void stop() {
		mFileList = null;
		super.stop();
	}
	

}
